package sk.dvsk.maven.doxia.macro;

import java.io.IOException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;

public class Snippet {

	private static final Pattern START_SNIPPET = Pattern.compile("START SNIPPET:\\s*(\\S+)");
	private static final Pattern END_SNIPPET = Pattern.compile("END SNIPPET:\\s*(\\S+)");
	private static final String DEFAULT_STYLE = "margin:1em 7px;"
		+ "padding:12px;"
		+ "background-color:#FFFFFF;"
		+ "border:1px solid #888888;"
		+ "color:#000000;";
	
	private int firstLine = 0;
	private String snippetCode;
	private String codeType;
	
	public Snippet(String id, URL url, String encoding) throws IOException {
		StringBuffer snippet = new StringBuffer();
		LineIterator lines = IOUtils.lineIterator(url.openStream(), encoding); 
		try {
			boolean include = id == null;
			int lineCounter = 0;
			while(lines.hasNext()) {
				String line = lines.nextLine();
				lineCounter++;
				
				if(mach(line, START_SNIPPET, id)) {
					include = true;
					firstLine = lineCounter;
				}
				else if(mach(line, END_SNIPPET, id)) {
					break;
				}
				else if(include == true) {
					snippet.append(line).append('\n');
				}
			}
			snippetCode = snippet.toString();
			codeType = getExtension(url);
		} finally {
			LineIterator.closeQuietly(lines);
		}
	}
	
	public String toString() {
//		return "<textarea name=\"code\" class=\"" + codeType + "\">" + snippetCode + "</textarea>";
		return "<pre name=\"code\" class=\"" + toConfigString() + "\" style=\"" + DEFAULT_STYLE + "\">"
			+ trim(replace())
			+ "</pre>\n";
	}

	private String replace() {
		return snippetCode
			.replace("&", "&amp;")
			.replace("<", "&lt;")
			.replace(">", "&gt;")
			.replace("\t", "    ");
	}
	
	private String trim(String replace) {
		int minIndent = minIndent(replace);

		return minIndent == 0  ? replace : 
			replace.replaceAll("(^|\n) {" + minIndent + "}", "$1");
	}

	private static int minIndent(String replace) {
		int totalCount = Integer.MAX_VALUE;
		int currentCount = 0;
		boolean counting = true;
		
		for(int i = 0; i < replace.length(); i++) {
			char c = replace.charAt(i);
			if(c == '\n') counting = true;
			else if(!counting) continue;
			else if(Character.isWhitespace(c)) currentCount++;
			else {
				totalCount = Math.min(totalCount, currentCount);
				counting = false;
				currentCount = 0;
			}
		}
		return totalCount == Integer.MAX_VALUE ? 0 : totalCount;
	}

	private String toConfigString() {
		StringBuffer result = new StringBuffer(codeType);
		if(firstLine > 0)
			result.append(':').append("firstline[").append(firstLine).append(']');
		return result.toString();
	}

	private String getExtension(URL url) {
		String name = url.toString();
		return name.substring(name.lastIndexOf('.') + 1);
	}

	private boolean mach(String line, Pattern pattern, String id) {
		if(id == null) return false;
		Matcher m = pattern.matcher(line);
		return m.find() && id.equals(m.group(1));
	}

	public void setCodeType(String codeType) {
		if(codeType.startsWith(":"))
			this.codeType += codeType;
		else 
			this.codeType = codeType;
	}
}
